Skip to content

[stable33] fix(UserConfig): cast getTypedValue() result to string in getValueBool() to fix PHP 8.4 TypeError#59630

Closed
thereisnotime wants to merge 1012 commits intonextcloud:masterfrom
thereisnotime:fix/userconfig-getvaluebool-strtolower-type-error
Closed

[stable33] fix(UserConfig): cast getTypedValue() result to string in getValueBool() to fix PHP 8.4 TypeError#59630
thereisnotime wants to merge 1012 commits intonextcloud:masterfrom
thereisnotime:fix/userconfig-getvaluebool-strtolower-type-error

Conversation

@thereisnotime
Copy link
Copy Markdown

Summary

Fixes #59629

PHP 8.4 made passing non-strings to strtolower() a fatal TypeError (previously a deprecation). UserConfig::getValueBool() calls strtolower() directly on the return value of getTypedValue(), which can return a non-string when stored value type metadata doesn't align with ValueType::BOOL.

In practice this manifests when user_ldap calls getValueBool($uid, 'user_ldap', 'isDeleted') — the stored isDeleted preference has no type metadata, causing getTypedValue() to return a non-string, which then breaks strtolower() in PHP 8.4.

Change

// Before
$b = strtolower($this->getTypedValue($userId, $app, $key, $default ? 'true' : 'false', $lazy, ValueType::BOOL));

// After
$b = strtolower((string)$this->getTypedValue($userId, $app, $key, $default ? 'true' : 'false', $lazy, ValueType::BOOL));

One-character fix: add (string) cast before the strtolower() call. This is safe and defensive — getTypedValue() is already declared to return string, so this is a no-op in the happy path and a guard for edge cases.

Impact

Without this fix, on PHP 8.4 + NC 33 with user_ldap enabled:

  • Every LDAP user request throws TypeError: strtolower(): Argument #1 ($string) must be of type string, string given
  • Desktop clients cannot authenticate and prompt for re-login
  • The web UI returns 500 Internal Server Error for LDAP users

Related

susnux and others added 30 commits March 17, 2026 23:36
…le33

[stable33] fix: provide `canDownload` helper for shares and use it where appropriate
Signed-off-by: Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
…line

Signed-off-by: Joas Schilling <coding@schilljs.com>
As we do it with other information of the user, we now use the known value
of a users displayname, and leave the updating to the background job. This
improves performance of user facing actions where the display name is
required and reduces queries to the LDAP server that are typically more
expensive.

Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
…le33

[stable33] fix(comments): Correctly treat end of message as end of code block/in…
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
…le33

[stable33] fix(files_external): properly handle API errors
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
Signed-off-by: Anna Larch <anna@nextcloud.com>
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.3.2 to 3.3.3.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](cure53/DOMPurify@3.3.2...3.3.3)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-version: 3.3.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
This is important especially for local development, as certificate are

self-signed.

Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
…le33

[stable33] fix(LDAP): use displayname from DB, before reaching out to LDAP
…yarn/build/frontend-legacy/stable33/dompurify-3.3.3

[stable33] chore(deps): Bump dompurify from 3.3.2 to 3.3.3 in /build/frontend-legacy
…le33

[stable33] fix(files): fix tab navigation from select all checkbox to batch actions
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
…le33

[stable33] fix: add fallback to raw path info
…4000 to 32000

Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
…le33

[stable33] fix: Add missing Attribute and fix parameter type in renewpassword route
…le33

[stable33] fix(files_sharing): respect config to skip certificate verification
…le33

[stable33] fix(bg_jobs): store job argument as a text, increase length cap to 32000
@szaimen szaimen added 3. to review Waiting for reviews high labels Apr 15, 2026
@szaimen szaimen added this to the Nextcloud 34 milestone Apr 15, 2026
@szaimen
Copy link
Copy Markdown
Contributor

szaimen commented Apr 15, 2026

Hi @thereisnotime please always target the master branch first. Then we can look into backporting to required stable branchs. Thanks!

@szaimen szaimen added 2. developing Work in progress and removed 3. to review Waiting for reviews labels Apr 15, 2026
@szaimen szaimen removed this from the Nextcloud 34 milestone Apr 15, 2026
@szaimen szaimen changed the title fix(UserConfig): cast getTypedValue() result to string in getValueBool() to fix PHP 8.4 TypeError f[stable33] ix(UserConfig): cast getTypedValue() result to string in getValueBool() to fix PHP 8.4 TypeError Apr 15, 2026
@szaimen szaimen changed the title f[stable33] ix(UserConfig): cast getTypedValue() result to string in getValueBool() to fix PHP 8.4 TypeError f[stable33] fix(UserConfig): cast getTypedValue() result to string in getValueBool() to fix PHP 8.4 TypeError Apr 15, 2026
@szaimen szaimen changed the title f[stable33] fix(UserConfig): cast getTypedValue() result to string in getValueBool() to fix PHP 8.4 TypeError [stable33] fix(UserConfig): cast getTypedValue() result to string in getValueBool() to fix PHP 8.4 TypeError Apr 15, 2026
@artonge
Copy link
Copy Markdown
Collaborator

artonge commented Apr 15, 2026

when getTypedValue() (declared as returning string) returns a value that violates its own return type, the TypeError is thrown at the call site (line 688) rather than inside getTypedValue()

Then maybe we should fix getTypedValue() so that it returns the correct type?

@artonge
Copy link
Copy Markdown
Collaborator

artonge commented Apr 15, 2026

Good catch on the confusing error message — you're right to question it.

Also, please at least remove AI boilerplate when answering, this just sound disrespectful :)

@thereisnotime thereisnotime changed the base branch from stable33 to master April 15, 2026 10:31
@thereisnotime thereisnotime requested review from sorbaugh and removed request for a team April 15, 2026 10:32
@thereisnotime
Copy link
Copy Markdown
Author

Retargeted to master, thanks for the heads up.

On fixing getTypedValue() instead — that's a fair point, but I've gone through the code and can't find a clear path where it returns a non-string. Values come from the DB as strings, decryptSensitiveValue takes string &$value by ref, the BOOL rename path returns '1'/'0'. Nothing obvious.

The (string) cast is a defensive fix that works in production, but I'll be the first to admit the root cause isn't fully understood. If you have a theory on what getTypedValue() is actually returning, happy to dig into it and do a proper fix instead.

@thereisnotime
Copy link
Copy Markdown
Author

Closing in favour of a clean PR based directly on master. The previous branch was cloned from stable33 causing a huge diff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: NC 33 / PHP 8.4: TypeError in UserConfig::getValueBool() — strtolower() receives non-string from getTypedValue()